package com.cnebula.openapi.auth.provider;

import java.util.HashMap;
import java.util.Map;

import com.cnebula.openapi.auth.AuthOptions;
import com.cnebula.openapi.auth.exception.OAuthGrantTypeUnsupported;
import com.cnebula.openapi.auth.service.ClientAppService;
import com.cnebula.openapi.auth.service.OAuthService;
import com.cnebula.openapi.auth.service.SignService;
import com.cnebula.openapi.auth.util.RestUtil;
import com.cnebula.openapi.auth.vo.AccessToken;
import com.cnebula.openapi.auth.vo.AuthCode;
import com.cnebula.openapi.auth.vo.ClientApp;

import io.vertx.core.Future;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;

public class OAuthProvider {

	SignService signService;
	OAuthService oauthService;
	ClientAppService clientAppService;
	private final AuthOptions options;

	public OAuthProvider(SignService signService, OAuthService oauthService,
			ClientAppService clientAppService, AuthOptions options) {
		this.signService = signService;
		this.oauthService = oauthService;
		this.clientAppService = clientAppService;
		this.options = options;
	}

	/**
	 * 获取服务访问令牌
	 * 
	 * @param context
	 */
	public void getAccessToken(RoutingContext context) {
		JsonObject body = context.getBodyAsJson();

		String tenantId = body.getString("tenant_id");
		String timestamp = body.getString("timestamp");
		String signMethod = body.getString("sign_method");
		String sign = body.getString("sign");
		String clientKey = body.getString("client_id");
		String code = body.getString("code");
		String grantType = body.getString("grant_type");

		Map<String, String> requiredParams = new HashMap<String, String>();
		requiredParams.put("client_id", clientKey);
		requiredParams.put("code", code);
		requiredParams.put("tenant_id", tenantId);
		requiredParams.put("timestamp", timestamp);
		requiredParams.put("sign_method", signMethod);
		requiredParams.put("sign", sign);
		requiredParams.put("grant_type", grantType);
		if(!RestUtil.checkRequired(requiredParams, context)) {
			return;
		}
		if(!grantType.equals(OAuthService.GANT_TYPE)) {
			RestUtil.responseError(new OAuthGrantTypeUnsupported(), context);
			return;
		}

		Map<String, String> signParams = new HashMap<String, String>();
		signParams.put("client_id", clientKey);
		signParams.put("code", code);
		signParams.put("tenant_id", tenantId);
		signParams.put("timestamp", timestamp);
		signParams.put("sign_method", signMethod);
		signParams.put("grant_type", grantType);

		
		
		//验证合法性
		Future<AuthCode> checkFuture = Future.future();
		oauthService.checkCode(code).
		compose(v -> clientAppService.checkKey(clientKey, tenantId, context.request().remoteAddress())).
		setHandler(h -> {
			if (h.succeeded()) {
				ClientApp clientApp = h.result();
				try {
					signService.check(signParams, clientApp.clientSecret, Long.parseLong(timestamp), sign);
					checkFuture.complete();
				} catch (Exception e) {
					checkFuture.fail(e);
				}
			} else {
				checkFuture.fail(h.cause());
			}
			
		});
		
		checkFuture.compose(h ->{
			//授权
			Future<AccessToken> f = oauthService.authorize(code);
			return f;
		}).setHandler(h ->{
			if (h.succeeded()) {
				AccessToken accessToken = h.result();
				RestUtil.responseResult(accessToken.toString(), context);
			} else {
				Throwable e = h.cause();
				RestUtil.responseError(e, context);
			}
		});
	}
}
